#ifndef INC_CLIENT_H_
#define INC_CLIENT_H_

#include "misc/Interface.h"
#include "misc/UDPNet.h"
#include "misc/MultiNet.h"
#include "misc/Event.h"
#include "client/net/cMsg.h"
#include <Poco/Runnable.h>
#include <Poco/Thread.h>
#include <Poco/Mutex.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Thread.h>
#include <Poco/ThreadPool.h>

#define PROCESS_EVENT "ACTIVATE_PROCESSING"
#define QUIT_EVENT "QUIT_EVENT"
#define _MIN_PORT_RANGE_ 4000
#define _MAX_PORT_RANGE_ 5000

#define ACKMAP std::map<std::string, std::map<unsigned long, std::string> >
/*********************************************************/
class Client : public Poco::Runnable
{
private:
	// Friends
	friend class cAnnounce;
	friend class cRingReply;
	friend class cRingDeny;
	friend class cRingDisconnect;
	friend class cRingRequest;
	friend class cDiscovery;
	friend class cKeepAlive;
	friend class cMsg;
	friend class cAck;
	friend class cExecute;
	friend class cData;
	friend class cPut;
	friend class cGet;
	friend class cuiPut;
	friend class cuiGet;

	// Members
	mutable Poco::Mutex		mutex;			// Mutual exclusion object
	Poco::Thread			lThread;		// Thread handle
	Poco::Net::SocketAddress	nsAddr;			// The nameserver address 
	Poco::Net::SocketAddress	ringAddr;		// The server address we will be connecting to in our ring
	Poco::ThreadPool		tPool;			// Thread for handling jobs
	ACKMAP				ackmap;			// messages waiting for ack
	std::string			ringName;		// Name of the ring we want to connect to
	UDPNet*				net;			// Unicast class ( UDPNet )
	MultiNet*			multicast;		// Multicast class ( MultiNet )
	bool				quitFlag;		// Flags a quit to the local thread
	unsigned long 			counter;		// Counter for unique identification of packets

	// Methods
	void run();						// Run the main client code ( runs in seperate thread! )
	unsigned long getID();					// Returns a unique id for packet identification

	// Construction & Destruction
	Client() { net = 0; counter = 0; };			// Constructor
	Client(const Client&);					// Copy Constructor
	Client& operator=(const Client&);			// Assignment operator

public:
	// Methods
	void start(const std::string&);				// Start the client
	void stop();						// Stops the client
	void wait();						// Wait for a quit event by either user input or an unexpected exception

	// Network methods
	bool send(const cMsg*);					// Send a message to the stored response address
	bool sendTo(const cMsg*, const std::string&);		// Send a message to a specified address
	bool waitForAck(const std::string&, const unsigned long&);	// Wait for an ack for a specified message id
	void broadcast(const cMsg*);				// Broadcast a message on the multicast group

	// Information retrieval methods
	std::string getLocalAddress() const;			// Returns the local address

	// Constructor & Destructor
	static Client& Instance();				// Singleton instance retrieval
	virtual ~Client() {};					// Destructor
};
/*********************************************************/
#endif // INC_CLIENT_H_
